package com.ynnu.changming.majiang_algorithm;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by bjzhaoxin on 2018/4/2.
 */
public class AIUtil {
    public static double calc(List<Integer> input, List<Integer> guiCard) {
        List<Integer> cards = new ArrayList<>();
        for (int i = 0; i < MaJiangDef.MAX_NUM; i++)

        {
            cards.add(0);
        }
        for (int c : input) {
            cards.set(c - 1, cards.get(c - 1) + 1);
        }

        int guiNum = 0;
        for (int gui : guiCard) {
            guiNum += cards.get(gui - 1);
            cards.set(gui - 1, 0);
        }

        List<Integer> ting = HuUtil.isTingCard(cards, guiNum);
        if (!ting.isEmpty()) {
            return ting.size() * 10;
        }

        long wan_key = 0;
        long tong_key = 0;
        long tiao_key = 0;
        long feng_key = 0;
        long jian_key = 0;

        for (int i = MaJiangDef.WAN1; i <= MaJiangDef.WAN9; i++) {
            int num = cards.get(i - 1);
            wan_key = wan_key * 10 + num;
        }
        for (int i = MaJiangDef.TONG1; i <= MaJiangDef.TONG9; i++) {
            int num = cards.get(i - 1);
            tong_key = tong_key * 10 + num;
        }
        for (int i = MaJiangDef.TIAO1; i <= MaJiangDef.TIAO9; i++) {
            int num = cards.get(i - 1);
            tiao_key = tiao_key * 10 + num;
        }
        for (int i = MaJiangDef.FENG_DONG; i <= MaJiangDef.FENG_BEI; i++) {
            int num = cards.get(i - 1);
            feng_key = feng_key * 10 + num;
        }
        for (int i = MaJiangDef.JIAN_ZHONG; i <= MaJiangDef.JIAN_BAI; i++) {
            int num = cards.get(i - 1);
            jian_key = jian_key * 10 + num;
        }

        List<List<AITableInfo>> tmp = new ArrayList<>();

        List<AITableInfo> wanAITableInfo = AITable.table.get(wan_key);
        tmp.add(wanAITableInfo);

        List<AITableInfo> tongAITableInfo = AITable.table.get(tong_key);
        tmp.add(tongAITableInfo);

        List<AITableInfo> tiaoAITableInfo = AITable.table.get(tiao_key);
        tmp.add(tiaoAITableInfo);

        List<AITableInfo> fengAITableInfo = AITableFeng.table.get(feng_key);
        tmp.add(fengAITableInfo);

        List<AITableInfo> jianAITableInfo = AITableJian.table.get(jian_key);
        tmp.add(jianAITableInfo);

        List<Double> ret = new ArrayList<>();
        calcAITableInfo(ret, tmp, 0, false, 0.d);

        Double d = Collections.max(ret);
        return d;
    }

    private static void calcAITableInfo(List<Double> ret, List<List<AITableInfo>> tmp, int index, boolean jiang,
                                        double cur) {
        if (index >= tmp.size()) {
            if (jiang) {
                ret.add(cur);
            }
            return;
        }

        List<AITableInfo> aiTableInfos = tmp.get(index);
        for (AITableInfo aiTableInfo : aiTableInfos) {
            if (jiang) {
                if (aiTableInfo.jiang == false) {
                    calcAITableInfo(ret, tmp, index + 1, jiang, cur + aiTableInfo.p);
                }
            } else {
                calcAITableInfo(ret, tmp, index + 1, aiTableInfo.jiang, cur + aiTableInfo.p);
            }
        }
    }


    //	输入六个牌的编码 和 鬼牌 ====》》》 判断该出哪一张牌
    public static int outAI(List<Integer> input, List<Integer> guiCard) {
        int ret = 0;

        //		Double.MIN_VALUE表示的是64位双精度值能表示的最小正数。
        double max = Double.MIN_VALUE;

//		42个麻将数量+1
        int[] cache = new int[MaJiangDef.MAX_NUM + 1];

//		c: 1 2 2 19 19 28
        for (Integer c : input) {
            if (cache[c] == 0) {
//				如果鬼牌里不包含 c：1 2 2 19 19 28
                if (!guiCard.contains(c)) {

                    List<Integer> tmp = new ArrayList<>(input);
                    tmp.remove(c);
                    double score = calc(tmp, guiCard);
                    if (score > max) {
                        max = score;
                        ret = c;
                    }
                }
            }
            cache[c] = 1;
        }
        return ret;
    }

    //	是否有吃
    public static boolean chiAI(List<Integer> input, List<Integer> guiCard, int card, int card1, int card2) {
        if (guiCard.contains(card) || guiCard.contains(card1) || guiCard.contains(card2)) {
            return false;
        }

        if (Collections.frequency(input, card1) < 1 || Collections.frequency(input, card2) < 1) {
            return false;
        }

        double score = calc(input, guiCard);

        List<Integer> tmp = new ArrayList<>(input);
        tmp.remove((Integer) card1);
        tmp.remove((Integer) card2);
        double scoreNew = calc(tmp, guiCard);

        return scoreNew >= score;
    }

    //
    public static ArrayList<Integer> chiAI(List<Integer> input, List<Integer> guiCard, int card) {
        ArrayList<Integer> ret = new ArrayList<>();
        if (guiCard.contains(card)) {
            return ret;
        }

        double score = calc(input, guiCard);
        double scoreNewMax = 0;

        int card1 = 0;
        int card2 = 0;

        if (Collections.frequency(input, card - 2) > 0 && Collections.frequency(input, card - 1) > 0
                && MaJiangDef.type(card) == MaJiangDef.type(card - 2)
                && MaJiangDef.type(card) == MaJiangDef.type(card - 1)) {
            List<Integer> tmp = new ArrayList<>(input);
            tmp.remove((Integer) (card - 2));
            tmp.remove((Integer) (card - 1));
            double scoreNew = calc(tmp, guiCard);
            if (scoreNew > scoreNewMax) {
                scoreNewMax = scoreNew;
                card1 = card - 2;
                card2 = card - 1;
            }
        }

        if (Collections.frequency(input, card - 1) > 0 && Collections.frequency(input, card + 1) > 0
                && MaJiangDef.type(card) == MaJiangDef.type(card - 1)
                && MaJiangDef.type(card) == MaJiangDef.type(card + 1)) {
            List<Integer> tmp = new ArrayList<>(input);
            tmp.remove((Integer) (card - 1));
            tmp.remove((Integer) (card + 1));
            double scoreNew = calc(tmp, guiCard);
            if (scoreNew > scoreNewMax) {
                scoreNewMax = scoreNew;
                card1 = card - 1;
                card2 = card + 1;
            }
        }

        if (Collections.frequency(input, card + 1) > 0 && Collections.frequency(input, card + 2) > 0
                && MaJiangDef.type(card) == MaJiangDef.type(card + 1)
                && MaJiangDef.type(card) == MaJiangDef.type(card + 2)) {
            List<Integer> tmp = new ArrayList<>(input);
            tmp.remove((Integer) (card + 1));
            tmp.remove((Integer) (card + 2));
            double scoreNew = calc(tmp, guiCard);
            if (scoreNew > scoreNewMax) {
                scoreNewMax = scoreNew;
                card1 = card + 1;
                card2 = card + 2;
            }
        }

        if (scoreNewMax > score) {
            ret.add(card1);
            ret.add(card2);
        }

        return ret;
    }


    //	是否有碰
    public static boolean pengAI(List<Integer> input, List<Integer> guiCard, int card, double award) {
        if (guiCard.contains(card)) {
            return false;
        }

        if (Collections.frequency(input, card) < 2) {
            return false;
        }

        double score = calc(input, guiCard);

        List<Integer> tmp = new ArrayList<>(input);
        tmp.remove((Integer) card);
        tmp.remove((Integer) card);
        double scoreNew = calc(tmp, guiCard);

        return scoreNew + award >= score;
    }

    //	是否有杠
    public static boolean gangAI(List<Integer> input, List<Integer> guiCard, int card, double award) {
        if (guiCard.contains(card)) {
            return false;
        }

        if (Collections.frequency(input, card) < 3) {
            return false;
        }

        double score = calc(input, guiCard);

        List<Integer> tmp = new ArrayList<>(input);
        tmp.remove((Integer) card);
        tmp.remove((Integer) card);
        tmp.remove((Integer) card);
        tmp.remove((Integer) card);
        double scoreNew = calc(tmp, guiCard);

        return scoreNew + award >= score;
    }

    //	测试输出
    public static void testOut() {
        String init = "1万,2万,2万,1条,1条,东";
        String guiStr = "1万";


        //		"1万,2万,2万,1条,1条,东"  转为  1,2,2,19,19,28
        List<Integer> cards = MaJiangDef.stringToCards(init);

        List<Integer> gui = MaJiangDef.stringToCards(guiStr);  //输出一万对应的编码  （1）

//		out =28
        int out = outAI(cards, gui);


        System.out.println(MaJiangDef.cardToString(out));
    }

    public static void testChi() {
        String init = "1万,2万,2万,1条,1条,1筒,2筒,4筒,4筒,5筒";
        String guiStr = "1万";
        List<Integer> cards = MaJiangDef.stringToCards(init);
        List<Integer> gui = MaJiangDef.stringToCards(guiStr);


        System.out.print("是否有吃？");
        System.out.println(chiAI(cards, gui, MaJiangDef.stringToCard("3筒"), MaJiangDef.stringToCard("2筒"),
                MaJiangDef.stringToCard("4筒")));
        System.out.println(MaJiangDef.cardsToString(chiAI(cards, gui, MaJiangDef.stringToCard("3筒"))));
    }

    public static void testPeng() {
        String init = "1万,2万,2万,1条,1条,2筒,4筒,4筒";
        String guiStr = "1万";

//		字符串转字符数组编为麻将代码存储到cards中
        List<Integer> cards = MaJiangDef.stringToCards(init);


        List<Integer> gui = MaJiangDef.stringToCards(guiStr);

        System.out.print("是否有碰？");
        System.out.println(pengAI(cards, gui, MaJiangDef.stringToCard("2万"), 0.d));
    }


    public static void testGang() {
        String init = "1万,2万,2万,2万,3万,4万,4筒,4筒";
        String guiStr = "1万";
        List<Integer> cards = MaJiangDef.stringToCards(init);
        List<Integer> gui = MaJiangDef.stringToCards(guiStr);

        System.out.print("是否有杠？");
        System.out.println(gangAI(cards, gui, MaJiangDef.stringToCard("2万"), 1.d));
    }

    public static void gen() {

        //箭牌，风牌，普通牌型编码，生成表。
        AITableJian.gen();
        AITableFeng.gen();
        AITable.gen();
    }

    //	分别读取三个文件
    public synchronized static void load() {
//		majiang_ai_jian
        AITableJian.load();

//		majiang_ai_feng
        AITableFeng.load();

//		majiang_ai_normal
        AITable.load();
    }

    //	测试胡牌
    private static void testHu() {
        ArrayList<Integer> total = new ArrayList<>();

        //一万到白寿，循环34次
        for (int i = MaJiangDef.WAN1; i <= MaJiangDef.JIAN_BAI; i++) {
            total.add(i);
            total.add(i);
            total.add(i);
            total.add(i);
        }
        //得到136张牌，都加入到数组当中
        // size ==34*4==136张牌
        ArrayList<Integer> totallist = total;

//       随机打乱列表原来的顺序，和洗牌一样
        Collections.shuffle(total);

//		cards： 取到十四张牌
        ArrayList<Integer> cards = new ArrayList<>();
        for (int i = 0; i < 14; i++) {
            cards.add(total.remove(0));
        }

        //整理牌型
        Collections.sort(cards);
        //最初得到的十四张牌
//        System.out.println("before " + MaJiangDef.cardsToString(cards));
        System.out.println("初始状态下的14张牌 " + MaJiangDef.cardsToString(cards));

        //鬼牌
        List<Integer> gui = new ArrayList<>();

        int step = 0;

        //		开始出牌cards为手中的十四张牌
        while (!total.isEmpty()) {
            //判断是否满足胡牌的条件,满足条件则可以跳出循环
            if (HuUtil.isHuExtra(cards, gui, 0)) {

                System.out.println("当前已经满足胡牌的条件 " + step);
                Collections.sort(cards); //将胡牌按编号排列
                System.out.println("after（胡） " + MaJiangDef.cardsToString(cards));
                System.out.println("step " + step);
                System.out.println("还没有抓到的牌 ：" + MaJiangDef.cardsToString(total));

                break;
            }

            System.out.println("开始出牌！！");
//            System.out.println("第" + step + "次换牌");
            int out = outAI(cards, gui);   //判断因该出什么牌
            cards.remove((Integer) out);   //出牌
            System.out.print("出的牌：");
            System.out.println(MaJiangDef.cardToString(out));

            System.out.println("第" + step + "次换牌结束");
            System.out.println("当前牌型：" + MaJiangDef.cardsToString(cards));
            System.out.println("|||||_________________________________|||||");

            step++;


            System.out.println("       ");
            System.out.println("       ");

            System.out.println("|||||---------------------------------|||||");

            System.out.println("第" + step + "次换牌");

            System.out.println("开始抓牌！！");
            Integer remove = total.remove(0);
            cards.add(remove);  //从剩下的牌中抓牌
            System.out.print("抓到的牌：");
            System.out.println(MaJiangDef.cardToString(remove));
            System.out.println("当前牌型：" + MaJiangDef.cardsToString(cards));



        }


    }

    public static void main(String[] args) {
        // 需要生成文件时 加上gen()，先生成表，再进行查询。
//        gen();

        HuUtil.load();
        load();
//		测试输出
        testOut();
        testChi();
        testPeng();
        testGang();

        //测试胡牌算法
        testHu();
    }

}
